package iks.utils.collision
{
	import flash.display.*;
	import flash.geom.*;
	
	/**
	 * 位图碰撞检测类, 提供碰撞检测的静态方法;
	 * PS: 此碰撞检测类必须保证显示对象的root是主类, 而不是stage, 而且root对象没有移动, 显示对象没有旋转;
	 * @author StefanieKaka
	 */
	public final class BitmapDataHitTest
	{
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 公共域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 以像素的方式判断两个显示对象是否发生碰撞, 这是基于intersectionRectangle()的判断方法
		 * @param	target1 显示对象1
		 * @param	target2 显示对象2
		 * @param	accuracy 判断精度
		 * @return 碰撞范围true, 否则返回false
		 */
		public static function hitTestObject(target1 : DisplayObject, target2 : DisplayObject, accuracy : Number = 1.0) : Boolean
		{
			return intersectionRectangle(target1, target1, accuracy).width != 0;
		}
		
		/**
		 * 以像素碰撞检测的方式判断两个显示对象相交的矩形, 该矩形是包括两个显示对象像素重合区域, 该矩形的坐标是全局坐标
		 * @param	target1 显示对象1
		 * @param	target2 显示对象2
		 * @param	accuracy 比较的精度, 使用值的范围(0, 1]
		 * @return Rectangle对象, 如果width或者height为0, 则表示没有发生碰撞; width和height大于0, 表示发生碰撞
		 */
		public static function intersectionRectangle(target1 : DisplayObject, target2 : DisplayObject, accuracy : Number = 1.0) : Rectangle
		{
			if (accuracy <= 0 || accuracy > 1)
				throw new ArgumentError("accuracy参数不正确, 参数范围(0, 1]");
			
			// 首先判断显示对象的矩形范围相交
			var hitRect : Rectangle = getHitRectangle(target1, target2);
			if (hitRect.width * accuracy < 1 || hitRect.height * accuracy < 1)
				return new Rectangle();
			
			// 使用不能的颜色和混合模式在位图上位置
			var bmpd : BitmapData = new BitmapData(hitRect.width * accuracy, hitRect.height * accuracy, true, 0);
			bmpd.draw(target1, getDrawMatrix(target1, hitRect, accuracy, accuracy), new ColorTransform(1, 1, 1, 1, 255, -255, -255, 255));
			bmpd.draw(target2, getDrawMatrix(target2, hitRect, accuracy, accuracy), new ColorTransform(1, 1, 1, 1, -255, 255, -255, 255), BlendMode.ADD);
			
			// 获得包含相交像素的范围
			var intersectionRect : Rectangle = bmpd.getColorBoundsRect(0xFFFFFFFF, 0xFFFFFF00);
			
			// 释放掉位图资源
			bmpd.dispose();
			bmpd = null;
			
			if (intersectionRect.width != 0)
			{
				// 根据精度还原为实际的碰撞区域
				if (accuracy != 1)
				{
					intersectionRect.x /= accuracy;
					intersectionRect.y /= accuracy;
					intersectionRect.width /= accuracy;
					intersectionRect.height /= accuracy;
				}
				
				intersectionRect.x += hitRect.x;
				intersectionRect.y += hitRect.y;
			}
			
			return intersectionRect;
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 私有域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 在全局坐标中, 获得两个显示对象相交的矩形框
		 */
		private static function getHitRectangle(target1 : DisplayObject, target2 : DisplayObject) : Rectangle
		{
			if (target1.root == null || target2.root == null)
				return new Rectangle();
			
			var bound1 : Rectangle = target1.getRect(target1.root);
			var bound2 : Rectangle = target2.getRect(target2.root);
			
			return bound1.intersection(bound2);
		}
		
		/**
		 * 获得绘制时需要的Matrix对象
		 */
		private static function getDrawMatrix(target : DisplayObject, hitRect : Rectangle, scaleX : Number, scaleY : Number) : Matrix
		{
			var matrix : Matrix = target.transform.concatenatedMatrix;
			var rootMatrix : Matrix = target.root.transform.concatenatedMatrix;
			var globalPos : Point = target.localToGlobal(new Point());
			
			matrix.tx = (globalPos.x - hitRect.x) * scaleX;
			matrix.ty = (globalPos.y - hitRect.y) * scaleY;
			matrix.a = matrix.a / rootMatrix.a * scaleX;
			matrix.d = matrix.d / rootMatrix.d * scaleY;
			
			return matrix;
		}
	}

}

///////////////////////////////////////////////////////////////////////////////////////////////////
// end file

